home *** CD-ROM | disk | FTP | other *** search
- #include "amiga.h"
- #include "signals.h"
- #include "fifofd.h"
- #include "timers.h"
- #include "amigados.h"
- #include <exec/execbase.h>
- #include <dos/var.h>
- #include <workbench/startup.h>
- #include <proto/timer.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <sys/time.h>
- #include <pwd.h>
-
- struct Process *_us;
- struct timeinfo *_odd_timer;
- ULONG _odd_sig;
- long _startup_time;
- long _stack_size;
- struct Device *TimerBase;
-
- static char *empty_env = 0; /* A default empty environment */
- char **environ; /* Unix style environment variable list */
- char *_system_name;
-
- extern struct ExecBase *SysBase;
- extern struct passwd _amiga_user;
- extern main(int argc, char **argv, char **envp);
-
- static void nomem(void)
- {
- _fail("No memory");
- }
-
- static void *_xmalloc(unsigned n)
- {
- void *p = malloc(n);
-
- if (!p) nomem();
-
- return p;
- }
-
- static void *_xrealloc(void *p, unsigned n)
- {
- void *p2 = realloc(p, n);
-
- if (!p2) nomem();
-
- return p2;
- }
-
- static char *safe_copystr(char *str)
- {
- char *new;
-
- if (!str) str = "";
- new = malloc(strlen(str) + 1);
- if (!new) return 0;
- return strcpy(new, str);
- }
-
- static char *copystr(char *str)
- {
- char *new = safe_copystr(str);
-
- if (!new) nomem();
-
- return new;
- }
-
- void make_environ(void)
- /* Effect: Builds a UNIX style environ variable from the AmigaDOS environment.
- */
- {
- int env_count = 0;
- long env_len = 0;
- struct LocalVar *scan_env;
- char **new_environ, *env_text;
-
- for (scan_env = (struct LocalVar *)_us->pr_LocalVars.mlh_Head;
- scan_env->lv_Node.ln_Succ;
- scan_env = (struct LocalVar *)scan_env->lv_Node.ln_Succ)
- if (scan_env->lv_Node.ln_Type == LV_VAR &&
- !(scan_env->lv_Flags & (GVF_GLOBAL_ONLY | GVF_BINARY_VAR)))
- {
- /* We only handle local text variables */
- env_count++;
- env_len += 2 + strlen(scan_env->lv_Node.ln_Name) + scan_env->lv_Len;
- }
-
- new_environ = environ = (char **)_xmalloc(sizeof(char *) * (1 + env_count) +
- env_len);
- env_text = (char *)(environ + (1 + env_count));
- if (!environ) environ = &empty_env;
- else
- {
- for (scan_env = (struct LocalVar *)_us->pr_LocalVars.mlh_Head;
- scan_env->lv_Node.ln_Succ;
- scan_env = (struct LocalVar *)scan_env->lv_Node.ln_Succ)
- if (scan_env->lv_Node.ln_Type == LV_VAR &&
- !(scan_env->lv_Flags & (GVF_GLOBAL_ONLY | GVF_BINARY_VAR)))
- {
- /* We only handle local text variables */
- char *env_name = scan_env->lv_Node.ln_Name;
- int env_len = scan_env->lv_Len;
-
- *new_environ++ = env_text;
- while (*env_name) *env_text++ = *env_name++;
- *env_text++ = '=';
- env_name = scan_env->lv_Value;
- while (env_len--) *env_text++ = *env_name++;
- *env_text++ = '\0';
- }
- *new_environ = 0;
- }
- }
-
- /* _main routine.
- Hides the differences between wb & cli.
- Provides a unix-like environment (including coomand-line parsing &
- wildcard expansion)
- */
-
- #define DEFPATLEN 256
- #define NAMELEN 1024
-
- struct args
- {
- int size;
- int argc;
- char **argv;
- };
-
- static void make_argv(struct args *args, int argc)
- {
- args->size = argc;
- args->argc = 0;
- args->argv = _xmalloc(sizeof(char *) * argc);
- }
-
- static int safe_add_arg(struct args *args, char *argument, int copy)
- {
- char *arg_copy;
-
- if (copy) arg_copy = safe_copystr(argument);
- else arg_copy = argument;
- if (!arg_copy) return 0;
-
- if (args->argc >= args->size)
- {
- /* Make argv bigger */
- if (args->size * 2 < args->size + 16) args->size += 16;
- else args->size *= 2;
- args->argv = realloc(args->argv, sizeof(char *) * args->size);
- if (!args->argv) return 0;
- }
- args->argv[args->argc++] = arg_copy;
- return 1;
- }
-
- static void add_arg(struct args *args, char *argument, int copy)
- {
- if (!safe_add_arg(args, argument, copy)) nomem();
- }
-
- static void concat_args(struct args *args, struct args *add)
- {
- if (args->argc + add->argc > args->size)
- {
- args->size = (args->argc + add->argc) * 2;
- args->argv = _xrealloc(args->argv, sizeof(char *) * args->size);
- }
- memcpy(args->argv + args->argc, add->argv, add->argc * sizeof(char *));
- args->argc += add->argc;
- free(add->argv);
- }
-
- typedef enum { quote_none, quote_single, quote_double } quote_type;
- typedef enum { extract_normal, extract_test, extract_pattern } extract_type;
-
- static void extract(char *buf, char *start, char *end,
- quote_type type, extract_type extract)
- {
- char *res = buf;
-
- switch (type)
- {
- case quote_single:
- if (extract != extract_test)
- {
- buf[end - start] = '\0';
- memcpy(buf, start, end - start);
- }
- else strcpy(buf, "a"); /* Things in quotes are never patterns */
- break;
-
- case quote_none:
- while (start < end)
- {
- if (start[0] == '\\' && start[1])
- {
- start += 2;
- /* Wildcard are escaped */
- if (extract == extract_test) *res++ = 'a';
- else if (extract == extract_pattern)
- switch (start[-1])
- {
- case '?': case '#': case '(': case ')': case '|': case '[':
- case ']': case '~': case '%': case '*': case '\'':
- *res++ = '\'';
- default:
- *res++ = start[-1];
- break;
- }
- else *res++ = start[-1];
- }
- else *res++ = *start++;
- }
- *res++ = '\0';
- break;
-
- case quote_double:
- while (start < end)
- {
- if (start[0] == '*' && start[1])
- {
- start += 2;
- switch (start[-1])
- {
- case 'n': *res++ = '\n'; break;
- case 'e': *res++ = '\x1b'; break;
- default: *res++ = start[-1]; break;
- }
- }
- else *res++ = *start++;
- }
- *res++ = '\0';
- break;
- }
- }
-
- void _main(char *line)
- /* Effect: Call unix_main with wildcards in argc & argv expanded (like unix)
- Also, do some early amiga initialisation for emacs.
- */
- {
- struct args args, wildargs;
- char *pattern, *arg_start, *arg_end, *arg;
- quote_type arg_quoted;
- long patlen = DEFPATLEN;
- struct AnchorPath *anchor;
- struct timeval now;
-
- if (SysBase->LibNode.lib_Version < 37) XCEXIT(20);
-
- stdin->_file = 0;
- stdin->_flag = _IOREAD;
- stdout->_file = 1;
- stdout->_flag = _IOWRT;
- stderr->_file = 2;
- stderr->_flag = _IORW | _IONBF;
-
- _us = (struct Process *)FindTask(0);
- _odd_timer = _alloc_timer();
- if (!_odd_timer) _fail("Failed to create timer");
- _odd_sig = _timer_sig(_odd_timer);
- TimerBase = _odd_timer->io->tr_node.io_Device;
- GetSysTime(&now);
- _startup_time = now.tv_secs;
-
- /* These use _startup_time, so must be here */
- _init_fifo();
- _init_signals();
-
- if (_us->pr_CLI) _stack_size = ((struct CommandLineInterface *)BADDR(_us->pr_CLI))->cli_DefaultStack << 2;
- else _stack_size = _us->pr_StackSize;
-
- /* Make unix-like argc, argv (expand wildcards) */
- if (!line[0]) /* Workbench, create argc & argv from files passed */
- {
- extern struct WBStartup *WBenchMsg;
- int i;
- BPTR nilin = Open("NIL:",MODE_NEWFILE);
- BPTR nilout = Open("NIL:",MODE_NEWFILE);
- BPTR nilerr = Open("NIL:",MODE_NEWFILE);
-
- /* Initialise I/O. Nothing is available */
- if (!nilin || !nilout || !nilerr)
- {
- if (nilin) Close(nilin);
- if (nilout) Close(nilout);
- if (nilerr) Close(nilerr);
- nomem();
- }
- _init_unixio(nilin, TRUE, nilout, TRUE, nilerr, TRUE);
-
- /* Make argc, argv from Workbench parameters */
- make_argv(&args, WBenchMsg->sm_NumArgs);
-
- for (i = 0; i < WBenchMsg->sm_NumArgs; i++)
- {
- char filename[256];
-
- if (NameFromLock(WBenchMsg->sm_ArgList[i].wa_Lock, filename, 256))
- {
- AddPart(filename, WBenchMsg->sm_ArgList[i].wa_Name, 256);
- add_arg(&args, filename, TRUE);
- }
- /* else A parameter was lost, cry, cry, cry */
- }
- }
- else /* From CLI expand wildcards (with unix-like command line parsing) */
- {
- int close_error;
- BPTR in, out, error;
-
- /* Initialise I/O. Copy CLI info */
- in = Input();
- out = Output();
- close_error = FALSE;
- if ((error = _us->pr_CES) == 0)
- {
- close_error = TRUE;
- if ((error = Open("*", MODE_OLDFILE)) == 0)
- if ((error = Open("NIL:", MODE_OLDFILE)) == 0) nomem();
- }
- _init_unixio(in, FALSE, out, FALSE, error, close_error);
-
- make_argv(&args, 1);
-
- anchor = _xmalloc(sizeof(struct AnchorPath) + NAMELEN);
- anchor->ap_Strlen = NAMELEN;
- pattern = _xmalloc(DEFPATLEN);
- while (1)
- {
- long new_patlen;
- int wild;
-
- /* Skip white space */
- while (isspace(*line)) line++;
- if (!*line) break; /* End of command line */
-
- /* Extract next word */
- /* Words in double quotes are handled AmigaDOS style
- (+ filename expansion) */
- if (*line == '"')
- {
- line++;
- arg_start = line;
- /* Find end of word */
- while (*line && *line != '"')
- {
- /* * is an escape character inside double quotes
- (AmigaDOS compatibility) */
- if ((*line == '*') && line[1]) line++;
- line++;
- }
- arg_end = line;
- if (*line == '"') line++;
- arg_quoted = quote_double;
- }
- /* Words in single quotes are handled unix style */
- else if (*line == '\'')
- {
- line++;
- arg_start = line;
- /* Find end of word */
- while (*line && *line != '\'') line++;
- arg_end = line;
- if (*line == '\'') line++;
- arg_quoted = quote_single;
- }
- /* Unquoted words are handled unix style */
- else /* Plain word */
- {
- arg_start = line;
- /* Find end of word */
- while (*line && !isspace(*line))
- {
- if (*line == '\\' && line[1]) line++;
- line++;
- }
- arg_end = line;
- arg_quoted = quote_none;
- }
- arg = _xmalloc(arg_end - arg_start + 1);
- if (args.argc == 0) /* Command name is left untouched */
- {
- strncpy(arg, arg_start, arg_end - arg_start);
- arg[arg_end - arg_start] = 0;
- add_arg(&args, arg, FALSE);
- }
- else
- {
- new_patlen = (arg_end - arg_start) * 2 + 16;
- if (new_patlen > patlen)
- {
- free(pattern);
- pattern = _xmalloc(new_patlen);
- patlen = new_patlen;
- }
- extract(arg, arg_start, arg_end, arg_quoted, extract_test);
- wild = ParsePattern(arg, pattern, patlen);
- if (wild < 0)
- {
- *arg_end = 0;
- _fail("Invalid wildcard %s", arg_start);
- }
- if (!wild)
- {
- extract(arg, arg_start, arg_end, arg_quoted, extract_normal);
- add_arg(&args, arg, FALSE);
- }
- else
- {
- int none = TRUE;
- long error;
-
- anchor->ap_Flags = anchor->ap_Reserved = anchor->ap_BreakBits = 0;
- extract(arg, arg_start, arg_end, arg_quoted, extract_pattern);
- make_argv(&wildargs, 16);
- error = MatchFirst(arg, anchor);
- while (!error)
- {
- none = FALSE;
- if (!safe_add_arg(&wildargs, anchor->ap_Buf, TRUE))
- {
- error = ERROR_NO_FREE_STORE;
- break;
- }
- error = MatchNext(anchor);
- }
- MatchEnd(anchor);
- if (error != ERROR_NO_MORE_ENTRIES)
- _fail("Error expanding arguments");
- if (none)
- {
- extract(arg, arg_start, arg_end, arg_quoted, extract_normal);
- add_arg(&args, arg, FALSE);
- }
- else
- {
- tqsort(wildargs.argv, wildargs.argc);
- concat_args(&args, &wildargs);
- free(arg);
- }
- }
- }
- }
- free(pattern);
- free(anchor);
- }
-
- make_environ();
-
- if (!(_amiga_user.pw_name = getenv("USER"))) _amiga_user.pw_name = "user";
- if (!(_amiga_user.pw_gecos = getenv("USERNAME")))
- _amiga_user.pw_gecos = _amiga_user.pw_name;
- if (!(_amiga_user.pw_dir = getenv("HOME"))) _amiga_user.pw_dir = "s:";
- if (!(_amiga_user.pw_shell = getenv("SHELL"))) _amiga_user.pw_shell = "bin:sh";
- if (!(_system_name = getenv("HOSTNAME"))) _system_name = "amiga";
-
- main(args.argc, args.argv, environ);
- exit(0);
- }
-